Uzziniet, kā ar JavaScript AbortController efektīvi atcelt asinhronas operācijas, piemēram, fetch pieprasījumus un taimerus, lai iegūtu tīrāku un ātrāku kodu.
JavaScript AbortController: Asinhrono operāciju atcelšanas apgūšana
Mūsdienu tīmekļa izstrādē asinhronas operācijas ir visuresošas. Datu iegūšana no API, taimeru iestatīšana un lietotāju mijiedarbības apstrāde bieži ietver kodu, kas darbojas neatkarīgi un potenciāli ilgu laiku. Tomēr ir scenāriji, kad šīs operācijas ir jāatceļ, pirms tās pabeigtas. Šeit nāk palīgā AbortController
saskarne JavaScript valodā. Tā nodrošina tīru un efektīvu veidu, kā nosūtīt atcelšanas signālus DOM operācijām un citiem asinhroniem uzdevumiem.
Izpratne par nepieciešamību atcelt operācijas
Pirms iedziļināties tehniskajās detaļās, sapratīsim, kāpēc asinhrono operāciju atcelšana ir svarīga. Apsveriet šos izplatītos scenārijus:
- Lietotāja navigācija: Lietotājs uzsāk meklēšanas vaicājumu, izraisot API pieprasījumu. Ja viņš ātri pāriet uz citu lapu, pirms pieprasījums ir pabeigts, sākotnējais pieprasījums kļūst neatbilstošs un būtu jāatceļ, lai izvairītos no nevajadzīgas tīkla trafika un iespējamām blakusparādībām.
- Taimauta pārvaldība: Jūs iestatāt taimautu asinhronai operācijai. Ja operācija pabeidzas pirms taimauta termiņa beigām, jums vajadzētu atcelt taimautu, lai novērstu lieku koda izpildi.
- Komponentu noņemšana (unmounting): Front-end ietvaros, piemēram, React vai Vue.js, komponenti bieži veic asinhronus pieprasījumus. Kad komponents tiek noņemts, jebkuri ar to saistītie notiekošie pieprasījumi ir jāatceļ, lai izvairītos no atmiņas noplūdēm un kļūdām, ko izraisa atjaunināšana noņemtos komponentos.
- Resursu ierobežojumi: Resursu ierobežotās vidēs (piemēram, mobilajās ierīcēs, iegultajās sistēmās), nevajadzīgu operāciju atcelšana var atbrīvot vērtīgus resursus un uzlabot veiktspēju. Piemēram, atceļot liela attēla lejupielādi, ja lietotājs ritina garām šai lapas sadaļai.
Iepazīstinām ar AbortController un AbortSignal
AbortController
saskarne ir paredzēta, lai atrisinātu asinhrono operāciju atcelšanas problēmu. Tā sastāv no diviem galvenajiem komponentiem:
- AbortController: Šis objekts pārvalda atcelšanas signālu. Tam ir viena metode,
abort()
, ko izmanto, lai signalizētu par atcelšanas pieprasījumu. - AbortSignal: Šis objekts apzīmē signālu, ka operācija ir jāpārtrauc. Tas ir saistīts ar
AbortController
un tiek nodots asinhronajai operācijai, kurai jābūt atceļamai.
Pamata lietojums: Fetch pieprasījumu atcelšana
Sāksim ar vienkāršu piemēru, kā atcelt fetch
pieprasījumu:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Data:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});
// To cancel the fetch request:
controller.abort();
Paskaidrojums:
- Mēs izveidojam
AbortController
instanci. - Mēs iegūstam saistīto
AbortSignal
nocontroller
. - Mēs nododam
signal
uzfetch
opcijām. - Ja mums ir nepieciešams atcelt pieprasījumu, mēs izsaucam
controller.abort()
. .catch()
blokā mēs pārbaudām, vai kļūda irAbortError
. Ja tā ir, mēs zinām, ka pieprasījums tika atcelts.
AbortError apstrāde
Kad tiek izsaukts controller.abort()
, fetch
pieprasījums tiks noraidīts ar AbortError
. Ir ļoti svarīgi pareizi apstrādāt šo kļūdu savā kodā. To neizdarot, var rasties neapstrādāti solījumu (promise) noraidījumi un neparedzēta uzvedība.
Šeit ir robustāks piemērs ar kļūdu apstrādi:
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log('Data:', data);
return data;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
return null; // Or throw the error to be handled further up
} else {
console.error('Fetch error:', error);
throw error; // Re-throw the error to be handled further up
}
}
}
fetchData();
// To cancel the fetch request:
controller.abort();
Labākā prakse AbortError apstrādei:
- Pārbaudiet kļūdas nosaukumu: Vienmēr pārbaudiet, vai
error.name === 'AbortError'
, lai nodrošinātu, ka apstrādājat pareizo kļūdas veidu. - Atgrieziet noklusējuma vērtību vai izmetiet kļūdu atkārtoti: Atkarībā no jūsu lietojumprogrammas loģikas, jūs varat atgriezt noklusējuma vērtību (piem.,
null
) vai atkārtoti izmest kļūdu, lai to apstrādātu augstāk izsaukumu stekā. - Sakopiet resursus: Ja asinhronā operācija ir piešķīrusi kādus resursus (piemēram, taimerus, notikumu klausītājus), sakopiet tos
AbortError
apstrādātājā.
Taimeru atcelšana ar AbortSignal
AbortSignal
var izmantot arī, lai atceltu taimerus, kas izveidoti ar setTimeout
vai setInterval
. Tas prasa nedaudz vairāk manuāla darba, jo iebūvētās taimera funkcijas tieši neatbalsta AbortSignal
. Jums ir jāizveido pielāgota funkcija, kas klausās atcelšanas signālu un notīra taimeri, kad tas tiek aktivizēts.
function cancellableTimeout(callback, delay, signal) {
let timeoutId;
const timeoutPromise = new Promise((resolve, reject) => {
timeoutId = setTimeout(() => {
resolve(callback());
}, delay);
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new Error('Timeout Aborted'));
});
});
return timeoutPromise;
}
const controller = new AbortController();
const signal = controller.signal;
cancellableTimeout(() => {
console.log('Timeout executed');
}, 2000, signal)
.then(() => console.log("Timeout finished successfully"))
.catch(err => console.log(err));
// To cancel the timeout:
controller.abort();
Paskaidrojums:
- Funkcija
cancellableTimeout
kā argumentus pieņem atzvanu (callback), aizkavi unAbortSignal
. - Tā iestata
setTimeout
un saglabā taimauta ID. - Tā pievieno notikumu klausītāju
AbortSignal
, kas klausāsabort
notikumu. - Kad tiek aktivizēts
abort
notikums, notikumu klausītājs notīra taimeri un noraida solījumu (promise).
Notikumu klausītāju atcelšana
Līdzīgi kā ar taimeriem, jūs varat izmantot AbortSignal
, lai atceltu notikumu klausītājus. Tas ir īpaši noderīgi, ja vēlaties noņemt notikumu klausītājus, kas saistīti ar komponentu, kas tiek noņemts.
const controller = new AbortController();
const signal = controller.signal;
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
}, { signal });
// To cancel the event listener:
controller.abort();
Paskaidrojums:
- Mēs nododam
signal
kā opcijuaddEventListener
metodei. - Kad tiek izsaukts
controller.abort()
, notikumu klausītājs tiks automātiski noņemts.
AbortController React komponentos
React vidē varat izmantot AbortController
, lai atceltu asinhronas operācijas, kad komponents tiek noņemts. Tas ir būtiski, lai novērstu atmiņas noplūdes un kļūdas, ko izraisa atjaunināšana noņemtos komponentos. Šeit ir piemērs, izmantojot useEffect
āķi (hook):
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
setData(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
}
}
fetchData();
return () => {
controller.abort(); // Cancel the fetch request when the component unmounts
};
}, []); // Empty dependency array ensures this effect runs only once on mount
return (
{data ? (
Data: {JSON.stringify(data)}
) : (
Loading...
)}
);
}
export default MyComponent;
Paskaidrojums:
- Mēs izveidojam
AbortController
useEffect
āķa iekšpusē. - Mēs nododam
signal
uzfetch
pieprasījumu. - Mēs atgriežam sakopšanas funkciju no
useEffect
āķa. Šī funkcija tiks izsaukta, kad komponents tiks noņemts. - Sakopšanas funkcijas iekšpusē mēs izsaucam
controller.abort()
, lai atceltu fetch pieprasījumu.
Papildu lietošanas gadījumi
AbortSignal saķēdēšana
Dažreiz var rasties nepieciešamība saķēdēt vairākus AbortSignal
. Piemēram, vecākkomponentam var būt nepieciešams atcelt operācijas savos bērnkomponentos. To var panākt, izveidojot jaunu AbortController
un nododot tā signālu gan vecākkomponentam, gan bērnkomponentiem.
AbortController izmantošana ar trešo pušu bibliotēkām
Ja izmantojat trešās puses bibliotēku, kas tieši neatbalsta AbortSignal
, jums var nākties pielāgot savu kodu, lai tas darbotos ar bibliotēkas atcelšanas mehānismu. Tas var ietvert bibliotēkas asinhrono funkciju ietīšanu savās funkcijās, kas apstrādā AbortSignal
.
AbortController izmantošanas priekšrocības
- Uzlabota veiktspēja: Nevajadzīgu operāciju atcelšana var samazināt tīkla trafiku, CPU lietojumu un atmiņas patēriņu, tādējādi uzlabojot veiktspēju, īpaši ierīcēs ar ierobežotiem resursiem.
- Tīrāks kods:
AbortController
nodrošina standartizētu un elegantu veidu, kā pārvaldīt atcelšanu, padarot jūsu kodu lasāmāku un uzturamāku. - Atmiņas noplūžu novēršana: Asinhrono operāciju atcelšana, kas saistītas ar noņemtiem komponentiem, novērš atmiņas noplūdes un kļūdas, ko izraisa atjaunināšana noņemtos komponentos.
- Labāka lietotāja pieredze: Neatbilstošu pieprasījumu atcelšana var uzlabot lietotāja pieredzi, novēršot novecojušas informācijas parādīšanu un samazinot uztverto latentumu.
Pārlūku saderība
AbortController
ir plaši atbalstīts modernajos pārlūkos, ieskaitot Chrome, Firefox, Safari un Edge. Jūs varat pārbaudīt saderības tabulu MDN Web Docs, lai iegūtu jaunāko informāciju.
Polifili (Polyfills)
Vecākiem pārlūkiem, kas dabiski neatbalsta AbortController
, varat izmantot polifilu. Polifils ir koda daļa, kas nodrošina jaunākas funkcijas funkcionalitāti vecākos pārlūkos. Tiešsaistē ir pieejami vairāki AbortController
polifili.
Noslēgums
AbortController
saskarne ir spēcīgs rīks asinhrono operāciju pārvaldībai JavaScript valodā. Izmantojot AbortController
, jūs varat rakstīt tīrāku, veiktspējīgāku un robustāku kodu, kas graciozi apstrādā atcelšanu. Neatkarīgi no tā, vai jūs iegūstat datus no API, iestatāt taimerus vai pārvaldāt notikumu klausītājus, AbortController
var palīdzēt uzlabot jūsu tīmekļa lietojumprogrammu vispārējo kvalitāti.